#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# -----------------------------------------------------------------------------
"""
   cdocgen main function
"""

__version__    = "0.2b"   # Feb.12, 2012
#__version__    = "0.2a"   # Feb.4, 2012
#__version__    = "0.2"   # Feb.2, 2012
#__version__    = "0.1a" # Feb.1, 2012
#__version__    = "0.1"  # Jan.31, 2012

main_version = __version__

import sys

from visio.cvisio import cvisio
from visio.tvisio import tvisio
import word.cword as cword
from common.cgrammar import cgrammar

class cdoc(cgrammar):
    def __init__(self, name):
        cgrammar.__init__(self)
        self.fname = name
        self.tvisio = tvisio("trace")

    def active_office(self, inputname='', outputname=''):
        # 如果未指定输入，输出文件，使用源文件名字自动命名
        # 如果未指定输入，指定输出，使用文件
        # 如果指定输入，未指定输出，自动使用输入文件作为输出
        # 如果指定输入，指定输出，正常使用
        self.visio = cvisio(self.fname+'.vsd')
        if self.flag_get('visio'):
            return 
        if inputname == '' and outputname == '':
            self.word = cword.cword(self.fname+'.doc')
            self.word.open_from_template(self.fname+'.doc')
        elif inputname == '' and outputname != '':
            self.word = cword.cword(self.fname+'.doc')
            self.word.open_from_template(outputname)
        elif inputname != '':
            self.word = cword.cword(inputname)
            self.word.open_default(outputname)

    def extend_printer(self, name, header, exp, depth):
        # 获取忽略标志
        #print 'doxy header', header
        word_flag = not header.has_key('ignore')

        # 扩展
        print '-----Adding func:', name, '@depth:', depth, ', Draw word=', word_flag
        if self.flag_get('trace'):
            self.tvisio.draw_fun(name, exp, 0, 0, depth)
        elif self.flag_get('visio'):
            self.visio.draw_fun(name, exp, 0, 0, depth)
        elif self.flag_get('nodraw') == 0:
            if (word_flag):
                self.word.insert_fun(name, header)
            self.visio.draw_fun(name, exp, 0, 0, depth)
            if (word_flag):
                self.word.insert_visio_pic(self.visio)
        pass

def version_info():
    print 'version: ' + __version__

def usage():
    prog = sys.argv[0].split('\\')[-1]
    usagestr = 'Usage: ' + prog +' [OPTIONS] [FILES]'+ u"""
用于从C语言(目前仅支持C语言)中的doxygen注释生成详细设计文件。
支持自动绘制visio格式流程图，并解析函数头部形成函数说明表。
By <zkk@crscd.com.cn>, 2011 

[OPTIONS]选项说明：
      -d,   --depth=DEPTH       设置在visio中流程图的调用层数
                                将被函数头部注释中的@depth覆盖.
            --force-depth=DEPTH 强制设置调用层数，不能被@depth覆盖
      -e,   --enhance           使用增强模式(reserved)
      -i,   --input=INFILE      设置word输入文件
      -o,   --output=OUTFILE    设置word输出文件
      -k,   --keyword=KEYFILE   设置语言的关键字文件
      -v,   --verbose           向终端输出函数结构
      -t,   --text              文本模式，用于绘制visio图
            --visio             只进行visio绘图，不生成word文件
            --nodraw            不进行visio绘图，不生成word文件
            --filter=FILTER     用于过滤函数名称
      -h,   --help              帮助
            --version           打印版本信息

[FILES]文件名说明:
    支持 *.c, ??.c 通配符，支持通配符组合，如: "1.c module\*.c"等

如有疑问，随时联系. """
    #print usagestr
    print usagestr
    
    
"""
For generating visio file from c file source.
By default using stricter grammar check. 
    e.g. {} is neede for statements in if, else, while, etc
By <zkk@crscd.com.cn>, 2011 

      -d,   --depth=DEPTH       Set depth of flowchart in visio draw. 
                                Will be skipped by @depth in function.
            --force-depth=DEPTH Force set depth of flowchart in visio draw.
      -e,   --enhance           Try enhance mode, less grammar check.
      -v,   --verbose           Set silent to less console output.
      -i,   --input=INFILE      Set output filename for office document.
      -o,   --output=OUTFILE    Set output filename for office document.
            --visio             Only visio drawing.
            --nodraw            No visio drawing and word print.
            --filter=FILTER     Filter string for function name.
      -h,   --help              Help for the program.
            --version           Version print.

Any questions, please contact me for free. """

class arg_map:
    def __init__(self):
        self.m = {}

    def flag_set(self, key, value):
        self.m[key] = value

    def flag_update(self, dst):
        for k, v in self.m.items():
            dst.flag_set(k, v)

if __name__ == "__main__":
    """
    CDocgen的主函数
    """
    import common.cglobal as cglobal
    import clang.clex as clex
    import clang.cyacc as cyacc

    import getopt
    import glob

    try:
        # 获取选项参数列表
        #    有效option在opts中
        #    后续的参数全部在args中
        opts, args = getopt.getopt(sys.argv[1:], 
                                   "hk:d:i:o:etv",     # 短参数
                ["help", "keyword=", "depth=", "force-depth=", "filter=", "input=", "output=", 
                 "nodraw", "visio", "enhance", "verbose", "trace", "text", "version"])    # 长参数

        if (len(args) == 0 and len(opts)==0 ):
            usage()
            sys.exit(2)

        filelist = []
        if (len(args) > 0):
            names = args
            for files in names:
                temp = glob.glob(files)
                for name in temp:
                    if not name in filelist:
                        filelist.append(name)

            # 这是自动命名的文件
            docname = cglobal.get_short_doc_name(filelist[0])
            #print filelist, docname; sys.exit(1)

        input_file = ""
        output_file = ""
        keyword_file = ""
        enhance = False

        amap = arg_map()

        for o, a in opts:
            if o in ('-d', '--depth'):
                # 设置深度时
                amap.flag_set('depth', int(a))
            elif o in ('-e', '--enhance'):
                enhance = True
            elif o in ('-i', '--input'):
                # 设置输入参数
                input_file = cglobal.get_full_name(a)
                #print temp, input_file
            elif o in ('-o', '--output'):
                # 设置输出文件
                output_file = cglobal.get_full_name(a)
            elif o in ('-k', '--keyword'):
                # 设置输出文件
                keyword_file = cglobal.get_full_name(a)
                amap.flag_set('keyword', keyword_file)
            elif o in ('-v', '--verbose'):
                amap.flag_set('verbose', 1)
            elif o in ('-t', '--text'):
                amap.flag_set('text', 1)
            elif o in ('--force-depth'):
                amap.flag_set('force-depth', int(a))
            elif o in ('--filter'):
                # 设置过滤器
                amap.flag_set('filter', a)
            elif o in ('--trace'):
                amap.flag_set('nodraw', 1)
                amap.flag_set('trace', 1)
            elif o in ('--nodraw'):
                # 不绘图
                amap.flag_set('nodraw', 1)
            elif o in ('--visio'):
                # 只画visio
                amap.flag_set('visio', 1)
            elif o in ('-R', '--recursive'):
                amap.flag_set('recursive', 1)
            elif o in ('-h', '--help'):
                usage()
                sys.exit(2)
            elif o in ('--version'):
                version_info()
                sys.exit(2)
            else:
                assert False, 'unknown option'

        gfun = cdoc(docname)
        myclex = clex.clex(gfun.comment_map)
        if (keyword_file != ""):
            myclex.load_keyword_from_file(keyword_file)

        print "+++Program flags:", amap.m
        amap.flag_update(gfun)

        p = cyacc.cyacc(myclex, gfun)
        if (enhance):
            import clang.ceyacc as ceyacc
            p = ceyacc.cyacc(myclex, gfun)
        print '+++Input file:', input_file
        print '+++Output file:', output_file
        import win32com.client
        try:
            if (gfun.flag_get('nodraw') == 0):
                gfun.active_office(input_file, output_file)
            # 打开文件，解析内容
            for name in filelist:
                print '===Parsing file', name
                f=open(name)
                data = f.read()
                res = p.parse(data,debug=0)

        #except EOFError, err:
        #    pass
        except Exception, err:
        #except EOFError, err:
            # 针对office的故障
            print err
            for l in err:
                if (isinstance(l, str)):
                    print l
                elif (isinstance(l, tuple)):
                    for w in l:
                        print w

            #print err[2][2]

    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err) # will print something like "option -a not recognized"
        usage()
        sys.exit(2)

